package com.linchong.concurrency.atomic;

import com.linchong.concurrency.annoations.ThreadSafe;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * @author linchong
 * @version 1.0
 * @Date: 2020-12-08 12:40
 * @Description: ConcurrencyTest$AtomicBoolean，如何让某个代码只执行一次，不会重复
 */
@Slf4j
@ThreadSafe
public class AtomicExample6 {

	private static AtomicBoolean isHappened = new AtomicBoolean(false);

	/**
	 * 请求总数
	 */
	private static int clientTotal = 5000;

	/**
	 * 同时执行的线程数
	 */
	private static int threadTotal = 200;

	public static void main(String[] args) throws InterruptedException {
		ExecutorService executorService = Executors.newCachedThreadPool();
		//允许同时执行的并发请求数，
		// 阻塞进程，控制同一时间的请求的并发量
		// 适合控制同时并发的线程数
		final Semaphore semaphore = new Semaphore(threadTotal);

		//所有请求执行完，统计结果
		// 闭锁，调用countdownLatch.await()方法阻塞，其他线程调用countdownLatch.countDown()方法，减一，
		// 当计数器值为0时，程序继续执行
		// 可以阻塞线程，并保证线程在满足某种特定的条件下，继续执行
		// 适合保证线程执行完之后继续其他的处理
		final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
		// 模拟并发测试，并在所有线程执行完之后输出结果，两者结合
		for (int i = 0; i < clientTotal; i++) {
			executorService.execute(()->{
				try {
					//当前线程是否允许被执行，否则，阻塞
					semaphore.acquire();
					test();
					semaphore.release();
				} catch (InterruptedException e) {
					log.error("exception",e);
				}
				countDownLatch.countDown();
			});
		}
		//可以保证之前的countdown必须减为0
		// 即线程池中所有线程都执行完成，否则，一直阻塞
		countDownLatch.await();
		executorService.shutdown();
		log.info("isHappened:{}",isHappened);
	}

	private static void test(){
		//原子操作，保证只会执行一次
		if(isHappened.compareAndSet(false,true)){
			 log.info("execute...");
		}
	}
}
